package org.jberney.wvdexporter.ui;

import java.io.File;
import java.io.FilenameFilter;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.jberney.wvdexporter.io.WvdEncoder;
import org.jberney.wvdexporter.util.prefs.WvdExporterPreferences;

import com.xuggle.mediatool.IMediaCoder;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.MediaListenerAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IAddStreamEvent;
import com.xuggle.xuggler.Configuration;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;

import org.eclipse.wb.swt.SWTResourceManager;

public class WvdBrowser {

	public static final String APP_NAME = "Wvd Exporter";
	public static final Point MIN_SIZE = new Point(320, 200);
	public static final Point DEFAULT_SIZE = new Point(400, 500);

	protected Shell shell;
	protected Table table;

	protected void createContents() {

		this.shell = new Shell();
		this.shell.setMinimumSize(MIN_SIZE);
		this.shell.setSize(DEFAULT_SIZE);
		this.shell.setText(APP_NAME);
		this.shell.setLayout(new FormLayout());

		final Button btnExport = new Button(this.shell, SWT.NONE);
		btnExport.setFont(SWTResourceManager.getFont("Lucida Grande", 13,
				SWT.NORMAL));
		btnExport.setEnabled(false);
		btnExport.setText("Export...");
		btnExport.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent selectionEvent) {
				try {
					WvdBrowser.this.export();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});

		this.shell.setDefaultButton(btnExport);

		FormData formDataBtnExport = new FormData();
		formDataBtnExport.bottom = new FormAttachment(100, -6);
		formDataBtnExport.right = new FormAttachment(100, -6);
		btnExport.setLayoutData(formDataBtnExport);

		Button btnRefresh = new Button(this.shell, SWT.NONE);
		btnRefresh.setFont(SWTResourceManager.getFont("Lucida Grande", 13,
				SWT.NORMAL));
		btnRefresh.setText("Refresh");
		btnRefresh.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				WvdBrowser.this.refresh();
			}
		});

		FormData formDataBtnRefresh = new FormData();
		formDataBtnRefresh.top = new FormAttachment(btnExport, 0, SWT.TOP);
		formDataBtnRefresh.left = new FormAttachment(0, 6);
		btnRefresh.setLayoutData(formDataBtnRefresh);

		Composite composite = new Composite(this.shell, SWT.NONE);
		FormData formDataComposite = new FormData();
		formDataComposite.top = new FormAttachment(0, 12);
		formDataComposite.left = new FormAttachment(0, 12);
		formDataComposite.bottom = new FormAttachment(btnExport, -6);
		formDataComposite.right = new FormAttachment(100, -12);
		composite.setLayoutData(formDataComposite);

		this.table = new Table(composite, SWT.BORDER);
		this.table.setLinesVisible(true);
		this.table.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				boolean enabled = (e.item != null);
				btnExport.setEnabled(enabled);
			}
		});

		TableColumnLayout layout = new TableColumnLayout();
		composite.setLayout(layout);

		TableColumn column = new TableColumn(this.table, SWT.NONE);
		layout.setColumnData(column, new ColumnWeightData(100));

		this.refresh();

	}

	protected File[] getFiles(FilenameFilter filenameFilter) {

		File[] files = null;

		WvdExporterPreferences prefs = new WvdExporterPreferences();
		String moviePath = prefs.getBrowserMoviePath();
		File directory = new File(moviePath);

		if (directory.exists() && directory.isDirectory()) {

			File[] moviesArray = directory.listFiles(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					return name.equals("Movies");
				}
			});
			if (moviesArray.length == 1) {
				directory = moviesArray[0];
			}

			files = directory.listFiles(filenameFilter);

		}

		return files;

	}

	protected void refresh() {

		this.table.removeAll();

		File[] wvdFiles = this.getFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.toLowerCase().endsWith(".wvd");
			}
		});

		if (wvdFiles != null) {
			for (File wvdFile : wvdFiles) {
				TableItem tableItem = new TableItem(this.table, SWT.NONE);
				String fileName = wvdFile.getName();
				fileName = fileName.substring(0, fileName.lastIndexOf(".wvd"));
				tableItem.setText(fileName);
				tableItem.setData(wvdFile.getAbsolutePath());
			}
		}

	}

	protected void export() throws Exception {

		TableItem[] tableItems = this.table.getSelection();

		if (tableItems.length == 1) {

			TableItem tableItem = tableItems[0];
			String fileName = tableItem.getText();
			String absolutePath = tableItem.getData().toString();

			FileDialog fileDialog = new FileDialog(this.shell, SWT.SAVE);
			fileDialog.setText("Save");
			fileDialog.setFileName(fileName);
			String selected = fileDialog.open();

			final String needle = fileName.toLowerCase();

			if (selected != null) {

				File[] files = this.getFiles(new FilenameFilter() {
					public boolean accept(File dir, String name) {
						return name.toLowerCase().matches(
								"^" + needle + "\\.(wvd(_[\\d]+)?|wav)");
					}
				});

				long numBytes = 0;
				if (files != null) {
					for (File file : files) {
						numBytes += file.length();
					}
				}

				ExportProgressShell exportProgressShell = new ExportProgressShell(
						Display.getDefault(), numBytes);
				Runnable exportRunnable = new ExportRunnable(
						exportProgressShell, absolutePath, selected);
				Thread exportThread = new Thread(exportRunnable);
				exportThread.start();

			}

		}

	}

	public void open() {
		Display display = Display.getDefault();
		this.createContents();
		this.shell.open();
		this.shell.layout();
		while (!this.shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}

	private static class ExportRunnable implements Runnable {

		private ExportProgressShell exportProgressShell;
		private String absolutePath;
		private String selected;

		public ExportRunnable(ExportProgressShell exportProgressShell,
				String absolutePath, String selected) {
			this.exportProgressShell = exportProgressShell;
			this.absolutePath = absolutePath;
			if (!selected.endsWith(".mp4")) {
				selected += ".mp4";
			}
			this.selected = selected;
		}

		public void run() {

			IMediaWriter mediaWriter = null;

			try {

				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						ExportRunnable.this.exportProgressShell.open();
					}
				});

				WvdExporterPreferences prefs = new WvdExporterPreferences();
				String moviePath = prefs.getBrowserMoviePath();
				final WvdEncoder wvdEncoder = new WvdEncoder(moviePath, 0, 0);
				wvdEncoder.addProgressListener(this.exportProgressShell);

				File file = new File(absolutePath);

				mediaWriter = ToolFactory.makeWriter(this.selected);
				mediaWriter.addListener(new MediaListenerAdapter() {
					@Override
					public void onAddStream(IAddStreamEvent event) {
						IMediaCoder source = event.getSource();
						IContainer container = source.getContainer();
						int streamIndex = event.getStreamIndex();
						IStream stream = container.getStream(streamIndex);
						IStreamCoder streamCoder = stream.getStreamCoder();
						streamCoder.setGlobalQuality(100);
						Configuration.configure(
								System.getenv("XUGGLE_HOME")
										+ "/share/ffmpeg/libx264-lossless_ultrafast.ffpreset",
								streamCoder);
					}
				});

				wvdEncoder.encode(file, mediaWriter);

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (mediaWriter != null && mediaWriter.isOpen()) {
					mediaWriter.flush();
					mediaWriter.close();
				}
				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						ExportRunnable.this.exportProgressShell.close();
						ExportRunnable.this.exportProgressShell.dispose();
					}
				});
			}

		}
	}

	public static void main(String[] args) {
		WvdBrowser window = new WvdBrowser();
		window.open();
		System.exit(0);
	}

}